/**
 * 
 */
package com.linkage.im.handler;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.linkage.im.model.GroupCreateVo;
import com.linkage.im.model.UserVo;
import com.linkage.im.utils.UserInterfUtils;
import org.jim.common.*;
import org.jim.common.cache.redis.RedisCache;
import org.jim.common.cache.redis.RedisCacheManager;
import org.jim.common.message.MessageHelper;
import org.jim.common.packets.*;
import org.jim.common.protocol.IProtocol;
import org.jim.common.utils.ImKit;
import org.jim.common.utils.JsonKit;
import org.jim.server.command.AbstractCmdHandler;
import org.jim.server.command.CommandManager;
import org.jim.server.command.handler.JoinGroupReqHandler;
import org.jim.server.helper.redis.RedisMessageHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.tio.core.ChannelContext;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 群组handler
 * @author biao
 */
@Component
public class GroupHandler extends AbstractCmdHandler {

	private final Logger log = LoggerFactory.getLogger(this.getClass());

	@Override
	public Command command() {
		return Command.forNumber(25);
	}

	@Override
	public ImPacket handler(ImPacket packet, ChannelContext channelContext) throws Exception {
		/*
		 *创建群组
		 * 入参：用户列表（usercode，username）
		 * 遍历用户列表形成表名，生成UUID做群组id，然后绑定group，见loginReqHandler-bindunbindgroup
		 */
		GroupCreateVo groupCreateVo = JsonKit.toBean(packet.getBody(), GroupCreateVo.class);
		List<UserVo> userVoList = groupCreateVo.getUserList();
		String groupId = StrUtil.isEmpty(groupCreateVo.getGroupId())? UUID.fastUUID().toString(true) : groupCreateVo.getGroupId();
		//创建群组
		if(StrUtil.equals("1", groupCreateVo.getType())){
			RespBody resPacket = createGroup(groupCreateVo,channelContext);
			return ImKit.ConvertRespPacket(resPacket, channelContext);
		}
		//处理踢人、退出群组
		else if(StrUtil.equals("2", groupCreateVo.getType()) || StrUtil.equals("3", groupCreateVo.getType())){
			RespBody resPacket = dealOutGroup(groupId,userVoList);
			return ImKit.ConvertRespPacket(resPacket, channelContext);
		}
		//拉人，添加人员进群
		else if(StrUtil.equals("6", groupCreateVo.getType())){
			RespBody resPacket = dealInGroup(groupId,userVoList,channelContext);
			return ImKit.ConvertRespPacket(resPacket, channelContext);
		}
		//设置群组信息
		else {
			RespBody resPacket = setGroupInfo(groupId,groupCreateVo.getContent(),groupCreateVo.getType());
			return ImKit.ConvertRespPacket(resPacket, channelContext);
		}
	}
	/**
	 * 初始化绑定或者解绑群组;
	 */
	public void bindUnbindGroup(ChannelContext channelContext , List<User> userList, Group group)throws Exception{
		ImSessionContext imSessionContext = (ImSessionContext)channelContext.getAttribute();
		//添加当前群组到登录的用户群组中
		Client client = imSessionContext.getClient();
		User curUser = client.getUser();
		List<Group> groupList = curUser.getGroups();
		if(!groupList.contains(group)){
			groupList.add(group);
			curUser.setGroups(groupList);
			client.setUser(curUser);
		}
		for(User user : userList){
			if(!StrUtil.equals(user.getId(),curUser.getId())){
				//添加群组用户
				imConfig.getMessageHelper().addGroupUser(user.getId(),group.getGroup_id()+":user");
				//用户添加群组
				RedisCacheManager.getCache("user").listPushTail(user.getId()+":group",group.getGroup_id());
				//发进房间通知  COMMAND_JOIN_GROUP_NOTIFY_RESP
				JoinGroupNotifyRespBody joinGroupNotifyRespBody = new JoinGroupNotifyRespBody().setGroup(group.getGroup_id()).setUser(user);
				RespBody notifyRespBody = new RespBody(Command.COMMAND_JOIN_GROUP_NOTIFY_RESP,joinGroupNotifyRespBody);
				ImPacket joinGroupNotifyrespPacket = new ImPacket(Command.COMMAND_JOIN_GROUP_NOTIFY_RESP,notifyRespBody.toByte());
				ImAio.sendToGroup(group.getGroup_id(),joinGroupNotifyrespPacket);
				continue;
			}
			String userId = user.getId();
			if( group != null){
				boolean isStore = ImConst.ON.equals(imConfig.getIsStore());
				MessageHelper messageHelper = null;
				List<String> groupIds = null;
				if(isStore){
					messageHelper = imConfig.getMessageHelper();
					groupIds = messageHelper.getGroups(userId);
				}
				//绑定群组
				if(isStore && groupIds != null){
					groupIds.remove(group.getGroup_id());
				}
				ImPacket groupPacket = new ImPacket(Command.COMMAND_JOIN_GROUP_REQ,JsonKit.toJsonBytes(group));
				try {
					JoinGroupReqHandler joinGroupReqHandler = CommandManager.getCommand(Command.COMMAND_JOIN_GROUP_REQ, JoinGroupReqHandler.class);
					joinGroupReqHandler.bindGroup(groupPacket, channelContext);
				} catch (Exception e) {
					log.error(e.toString(),e);
				}
			}
		}
	}

	private RespBody createGroup(GroupCreateVo groupCreateVo,ChannelContext channelContext) throws Exception{
		log.info("进入创建群组方法");
		List<UserVo> userVoList = groupCreateVo.getUserList();
		String groupId = UUID.fastUUID().toString(true);
		String groupName = userVoList.stream().map(UserVo::getUserRealName).collect(Collectors.joining(","));
		List<User> userList = new ArrayList<>();
		userVoList.forEach(userVo ->{
			User user = new User();
			user.setNick(userVo.getUserRealName());
			user.setAvatar(userVo.getUserPhotoUrl());
			user.setId(userVo.getUserCode());
			user.setExtras(JSON.parseObject(JSON.toJSONString(userVo)));
			userList.add(user);
		});
		Group group = new Group();
		group.setGroup_id(groupId);
		group.setName(groupName);
		group.setUsers(userList);
		bindUnbindGroup(channelContext,userList, group);
		RespBody resPacket = new RespBody(Command.valueOf(26),
				MapUtil.builder().put("groupId",groupId).put("groupName",groupName).build());
		return resPacket;
	}

	/**
	 * 处理踢人、退出群组
	 * @param groupId
	 * @param users
	 */
	private RespBody dealOutGroup(String groupId, List<UserVo> users){
		for(UserVo user : users){
			//TODO 删除group:{groupId}:user中的数据
			RedisCacheManager.getCache(ImConst.GROUP).listRemove(groupId+":user",user.getUserCode());
			//TODO 删除user:{userId}:group中的数据
			RedisCacheManager.getCache(ImConst.USER).listRemove(user.getUserCode()+":group",groupId);
		}
		RespBody resPacket = new RespBody(Command.valueOf(26),
				MapUtil.builder().build());
		return resPacket;
	}

	/**
	 * 设置群组信息
	 * @param groupId
	 * @param content
	 * @param type
	 */
	private RespBody setGroupInfo(String groupId, String content, String type){
		RespBody resPacket = new RespBody(Command.valueOf(26));
		RedisCache groupCache = RedisCacheManager.getCache(ImConst.GROUP);
		// 设置群组名称
		if(StrUtil.equals("4",type)){
			Group group = groupCache.get(groupId+":"+ImConst.INFO , Group.class);
			group.setName(content);
			groupCache.put(groupId+":"+ImConst.INFO,group);
			resPacket.setMsg("设置群名称成功！").setCode(10000);
		}
		// 设置群公告
		else if(StrUtil.equals("5",type)){
			Group group = groupCache.get(groupId+":"+ImConst.INFO , Group.class);
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("notice",content);
			group.setExtras(jsonObject);
			groupCache.put(groupId+":"+ImConst.INFO,group);
			resPacket.setMsg("设置群公告成功！").setCode(10000);
		}else{
			resPacket.setMsg("操作类型不支持").setCode(10021);
		}
		return resPacket;
	}

	/**
	 * 拉人
	 * @param groupId
	 * @param userList
	 * @param channelContext
	 * @return
	 * @throws Exception
	 */
	private RespBody dealInGroup(String groupId,List<UserVo> userList,ChannelContext channelContext) throws Exception{
		RespBody resPacket = new RespBody(Command.valueOf(26));
		RedisCache userCache = RedisCacheManager.getCache(ImConst.USER);
		MessageHelper helper = new RedisMessageHelper();
		Group group = helper.getGroupUsers(groupId,2);
		//筛选用户
		List<User> users = new ArrayList<>();
		userList.forEach(x -> {
			User user = new User();
			user.setNick(x.getUserRealName());
			user.setAvatar(x.getUserPhotoUrl());
			user.setId(x.getUserCode());
			user.setExtras(JSON.parseObject(JSON.toJSONString(x)));
			List<String> groupList = userCache.listGetAll(x.getUserCode()+":"+ImConst.GROUP);
			if(!groupList.contains(groupId)){
				users.add(user);
			}
		});
		//绑定群组
		bindUnbindGroup(channelContext,users,group);
		resPacket.setMsg("增加群组人员成功！").setCode(10000);
		return resPacket;
	}
}
